/*
 * interrupts.cpp
 *
 *  Created on: 2021年3月2日
 *      Author: root
 */
#include <hardwarecommunication/interrupts.h>

using namespace myos::common;
using namespace myos::hardwarecommunication;

void printf(char* str);

void printfHex(uint8_t key);
InterruptHandler::InterruptHandler(uint8_t interruptNumber,InterruptManager *interruptManager){
	this->interruptNumber=interruptNumber;
	this->interruptManager=interruptManager;
	interruptManager->handlers[interruptNumber]=this;
	}

InterruptHandler::~InterruptHandler(){
	if(interruptManager->handlers[interruptNumber]==this){
		interruptManager->handlers[interruptNumber]=0;
	}
}

uint32_t InterruptHandler::HandleInterrupt(uint32_t esp){
	return esp;
}






InterruptManager::GateDescriptor InterruptManager::interruptDescriptorTable[256];

InterruptManager* InterruptManager::ActiveInterruptManager=0;


void InterruptManager::SetInterruptDescriptorTableEntry
	(
	uint8_t interruptNumber,
	uint16_t codeSegmentSelectorOffset,
	void (*handler)(),
	uint8_t DescriptorPrivilegeLevel,
	uint8_t DescriptorType
	)
{
	const uint8_t IDT_DESC_PRESENT=0x80;
	interruptDescriptorTable[interruptNumber].handlerAddressLowBits=((uint32_t)handler) & 0xFFFF;
	interruptDescriptorTable[interruptNumber].handlerAddressLowBits=(((uint32_t)handler) >> 16) & 0xFFFF;
	interruptDescriptorTable[interruptNumber].gdt_codeSefmentSelector=codeSegmentSelectorOffset;
	interruptDescriptorTable[interruptNumber].access=IDT_DESC_PRESENT | DescriptorType | (DescriptorPrivilegeLevel <<5 );
	interruptDescriptorTable[interruptNumber].reserved=0;
}

InterruptManager::InterruptManager(uint16_t hardwareInterruptOffeset,GlobalDescriptorTable *gdt,TaskManager* taskManager)
: picMasterCommand(0x20),
  picMasterData(0x21),
  picSlaveCommand(0xA0),
  picSlaveData(0xA1)
{
	this->taskManager=taskManager;
	this->hardwareInterruptOffeset=hardwareInterruptOffeset;
	uint32_t CodeSegment=gdt->CodeSegmentSelector();
	const uint16_t IDT_INTERRUPT_GATE=0xE;

	for(uint16_t i=0;i<256;i++){
		handlers[i]=0;
		SetInterruptDescriptorTableEntry(i,CodeSegment,&IgnoreInterruptRequest,0,IDT_INTERRUPT_GATE);
	}
	SetInterruptDescriptorTableEntry(0x20,CodeSegment,&HandleInterruptRequest0x00,0,IDT_INTERRUPT_GATE);
	SetInterruptDescriptorTableEntry(0x21,CodeSegment,&HandleInterruptRequest0x01,0,IDT_INTERRUPT_GATE);
	SetInterruptDescriptorTableEntry(0x2C,CodeSegment,&HandleInterruptRequest0x0C,0,IDT_INTERRUPT_GATE);

	picMasterCommand.Write(0x11);
	picSlaveCommand.Write(0x11);

	picMasterData.Write(0x20);
	picSlaveData.Write(0x28);

	picMasterData.Write(0x04);
	picSlaveData.Write(0x02);

	picMasterData.Write(0x01);
	picSlaveData.Write(0x01);

	picMasterData.Write(0x00);
	picSlaveData.Write(0x00);

	InterruptDescriptorTablePointer idt;
	idt.size=256*sizeof(GateDescriptor)-1;
	idt.base=(uint32_t)interruptDescriptorTable;
	asm volatile("lidt %0": :"m"(idt));
}

InterruptManager::~InterruptManager()
{

}
void InterruptManager::Activate()
{
	//一个时间段内只会有一个活动的中断向量
	if(ActiveInterruptManager!=0)
		ActiveInterruptManager->Deactivate();
	ActiveInterruptManager=this;
	asm("sti");
}

void InterruptManager::Deactivate()
{
	//一个时间段内只会有一个活动的中断向量
	if(ActiveInterruptManager==this)
		ActiveInterruptManager=0;
	asm("cli");
}

//中断编号和当前的堆栈指针
uint32_t InterruptManager::handleInterrupt(uint8_t interruptNumber,uint32_t esp)
{
	if(ActiveInterruptManager!=0)
	{
		return ActiveInterruptManager->DoHandleInterrupt(interruptNumber, esp);
	}

	return esp;
}

uint32_t InterruptManager::DoHandleInterrupt(uint8_t interruptNumber,uint32_t esp)
{
	if(handlers[interruptNumber]!=0){
		esp=handlers[interruptNumber]->HandleInterrupt(esp);
	}
	//当不是时间中断的时候，输出
	else if(interruptNumber!=hardwareInterruptOffeset){
		printf("UNHANDLE INTERRUPT 0x");
		printfHex(interruptNumber);
	}
	if(interruptNumber==hardwareInterruptOffeset){
		esp=(uint32_t)taskManager->Schedule((CPUState*) esp);
	}
	//重新映射硬件中断
	if(0x20<=interruptNumber&&interruptNumber<=0x30){
		picMasterCommand.Write(0x20);
		if(0x28<=interruptNumber&&interruptNumber<=0x30){
			picSlaveCommand.Write(0x20);
		}

	}
	return esp;
}


